package com.software.usercenter.utils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Author: grx
 * Description:
 */
public class CommandUtil {
    // run 方法，要执行一个命令就要创建一个进程来运行一个命令。
    // 要进行编译和运行，来确定这个类中的参数，包含3个参数。
    // 1.要进行编译的命令
    // 2.要是编译和运行都成功，则是标准输出的内容，放在一个文件中，用stdoutFile来表示。
    // 3.要是编译出错或者运行出错，则表示的是标准错误，放在stderrFile文件中。
    // Run方法用于进行创建进程并执行编译和运行命令。
    // cmd 表示要执行的命令, 比如 javac
    // stdoutFile 指定标准输出写到哪个文件中
    // stderrFile 执行标准错误写到哪个文件中
    // 进程的返回值用0来表示进程结束，-1表示的是进程没有结束，或者进程异常。
    public static int run(String language, String type, String path, String cmd, String stdoutFile,
                          String stderrFile) throws IOException, InterruptedException {
        // 进行多进程操作。
        // 用 Runtime 这样的类表示进程的创建。Runtime这个类在创建的时候，不用手动去创建。
        // 里边的实例只有一个，这就是设计模式中的“单例模式”，直接调用里边的.getRunTime().exec()方法即可。
        // 下边表示创建一个进程，用process表示。
        Process process = null;

        switch (language) {
            case "java":
                /*cmd = "cd /d d: && cd " + path + " && " + cmd;
                String[] args = {"cmd.exe", "/c", cmd};*/
                process = Runtime.getRuntime().exec(cmd);
                break;
            case "c":
                if (type.equals("compile")) {
//                    String[] command = new String[]{"D:\\softInstall\\Dev-Cpp\\MinGW64\\bin\\g++", "-o", "Solution", "Solution.cpp"};
                    String[] command = new String[]{"g++", "-o", "Solution", "Solution.c"};
                    ProcessBuilder pb1 = new ProcessBuilder(command);
                    pb1.directory(new File(path));
                    pb1.redirectOutput(new File(stderrFile));
                    pb1.redirectErrorStream(true);
                    process = pb1.start();
                } else {
                    ProcessBuilder pb1 = new ProcessBuilder(path  + "/Solution.exe");
                    pb1.directory(new File(path));
                    pb1.redirectInput(new File(type));
                    pb1.redirectOutput(new File(stdoutFile));
                    pb1.redirectErrorStream(true);
                    process = pb1.start();
                }
                /*ProcessBuilder pb1 = new ProcessBuilder(command1);
                pb1.directory(new File(path));
                pb1.redirectErrorStream(true);
                process = pb1.start();*/
                break;
            case "c++":
                if (type.equals("compile")) {
//                    String[] command = new String[]{"D:\\softInstall\\Dev-Cpp\\MinGW64\\bin\\g++", "-o", "Solution", "Solution.cpp"};
                    String[] command = new String[]{"g++", "-o", "Solution", "Solution.cpp"};
                    ProcessBuilder pb1 = new ProcessBuilder(command);
                    pb1.directory(new File(path));
                    pb1.redirectOutput(new File(stderrFile));
                    pb1.redirectErrorStream(true);
                    process = pb1.start();
                } else {
                    ProcessBuilder pb1 = new ProcessBuilder(path  + "/Solution.exe");
                    pb1.directory(new File(path));
                    pb1.redirectInput(new File(type));
                    pb1.redirectOutput(new File(stdoutFile));
                    pb1.redirectErrorStream(true);
                    process = pb1.start();
                }
                /*ProcessBuilder pb1 = new ProcessBuilder(command1);
                pb1.directory(new File(path));
                pb1.redirectErrorStream(true);
                process = pb1.start();*/
                break;
            case "python":
                cmd = "cd /d d: && cd " + path + " && " + cmd;
                String[] args1 = {"cmd.exe", "/c", cmd};
                process = Runtime.getRuntime().exec(args1);
                break;
        }



        // 当新的进程跑起来之后, 就需要获取到新进程的输出结果，结果无非有以下几种。
        // 1.要是标准输出中有内容，也就是下边的文件的内容不是空的，给标准输出进行重定向。
        if (stdoutFile != null) {
            // getInputStream 得到的是标准输出，得到里边的内容，为了后边进行重定向。
            InputStream stdoutFrom = process.getInputStream();
            BufferedReader bf = new BufferedReader(new InputStreamReader(stdoutFrom));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = bf.readLine()) != null) {
                sb.append(line);
            }
            String stdout = sb.toString();
            FileOutputStream stdoutTo = new FileOutputStream(stdoutFile);
            stdoutTo.write(stdout.getBytes());
            // 关闭流
            stdoutFrom.close();
            bf.close();
            stdoutTo.flush();
            stdoutTo.close();
        }

        // 同上，再针对标准错误进行重定向
        // 要是标准错误文件中有内容，就将输出的内容进行重定向。
        if (stderrFile != null) {
            // getErrorStream 得到的是标准错误
            InputStream stderrFrom = process.getErrorStream();
            // 表示弄了一个箱子，用来存放标准错误中的内容。
            FileOutputStream stderrTo = new FileOutputStream(stderrFile);
            int ch;
            while ((ch = stderrFrom.read()) != -1) {
                stderrTo.write(ch);
            }
            // 操作完文件，进行文件的关闭。
            stderrFrom.close();
            stderrTo.flush();
            stderrTo.close();
        }
        // 等待新的进程的结束，在结束退出码。就是等待刚创建的run进程的结束才获取退出码的
        int exitCode = 0;
        if (process != null && process.isAlive()) {
            exitCode = process.waitFor();// 等待一下，等新的进程运行结束
            process.destroy();
        }
        return exitCode;
    }

    /*public static void main(String[] args) {
        // 下边来进行调用。
        try {
            // run方法的返回值是int型的，0表示进程成功结束，-1表示的是错误。
            int ret = CommandUtil.run("","javac", "./stdout.txt", "./stderr.txt");
            System.out.println(ret);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }*/
}
